package com.b.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import com.b.domain.CoinRecord;
import com.b.domain.LikeRecord;
import com.b.domain.Video;
import com.b.domain.WatchHistory;
import com.b.repository.CategoryRepository;
import com.b.repository.VideoRepository;
import com.b.service.CoinRecordService;
import com.b.service.FavoriteService;
import com.b.service.LikeRecordService;
import com.b.service.RecommendationService;
import com.b.service.VideoService;
import com.b.service.WatchHistoryService;

/**
 * @author jdj
 */
@Service
public class RecommendationServiceImpl implements RecommendationService {
    
    @Autowired
    private VideoService videoService;
    
    @Autowired
    private LikeRecordService likeRecordService;
    
    @Autowired
    private FavoriteService favoriteService;
    
    @Autowired
    private CoinRecordService coinRecordService;
    
    @Autowired
    private WatchHistoryService watchHistoryService;
    
    @Autowired
    private VideoRepository videoRepository;
    
    @Autowired
    private CategoryRepository categoryRepository;

    @Override
    public List<Video> recommendVideos(Integer userId, PageRequest pageRequest) {
        try {
            // 1. 获取用户行为数据
            List<LikeRecord> userLikes = getUserLikes(userId);
            List<CoinRecord> userCoins = getUserCoins(userId);
            List<WatchHistory> userWatchHistory = getUserWatchHistory(userId);
            
            // 2. 计算用户对视频的兴趣分数
            Map<Integer, Double> userVideoScores = calculateUserVideoScores(userId, userLikes, userCoins, userWatchHistory);
            
            // 3. 如果用户没有行为数据，返回随机热门视频
            if (userVideoScores.isEmpty()) {
                List<Video> popularVideos = getPopularVideos(pageRequest);
                java.util.Collections.shuffle(popularVideos);
                return popularVideos;
            }
            
            // 4. 基于协同过滤推荐
            List<Video> recommendedVideos = collaborativeFiltering(userId, userVideoScores, pageRequest);
            
            // 5. 如果推荐结果不足，补充热门视频
            if (recommendedVideos.size() < pageRequest.getPageSize()) {
                List<Video> popularVideos = getPopularVideos(pageRequest);
                recommendedVideos.addAll(popularVideos);
                // 去重并限制数量
                recommendedVideos = recommendedVideos.stream()
                    .distinct()
                    .limit(pageRequest.getPageSize())
                    .collect(Collectors.toList());
            }
            
            // 6. 随机打乱推荐结果，确保每次返回不同的顺序
            java.util.Collections.shuffle(recommendedVideos);
            
            return recommendedVideos;
            
        } catch (Exception e) {
            e.printStackTrace();
            // 发生异常时返回随机热门视频
            List<Video> popularVideos = getPopularVideos(pageRequest);
            java.util.Collections.shuffle(popularVideos);
            return popularVideos;
        }
    }

    @Override
    public List<Video> getPopularVideos(PageRequest pageRequest) {
        try {
            // 获取所有已审核通过的视频
            List<Video> allVideos = videoService.getAll();
            
            // 过滤已审核通过的视频
            List<Video> approvedVideos = allVideos.stream()
                .filter(video -> "pass".equals(video.getResult()))
                .collect(Collectors.toList());
            
            // 按综合热度排序（播放量 + 点赞数*2 + 收藏数*3 + 投币数*5）
            approvedVideos.sort((v1, v2) -> {
                int score1 = calculatePopularityScore(v1);
                int score2 = calculatePopularityScore(v2);
                return Integer.compare(score2, score1); // 降序
            });
            
            // 分页
            int start = (int) pageRequest.getOffset();
            int end = Math.min(start + pageRequest.getPageSize(), approvedVideos.size());
            
            if (start >= approvedVideos.size()) {
                return new ArrayList<>();
            }
            
            return approvedVideos.subList(start, end);
            
        } catch (Exception e) {
            e.printStackTrace();
            return new ArrayList<>();
        }
    }

    @Override
    public List<Video> getVideosByCategory(Integer categoryId, PageRequest pageRequest) {
        try {
            // 获取所有已审核通过的视频
            List<Video> allVideos = videoService.getAll();
            
            // 过滤指定分类且已审核通过的视频
            List<Video> categoryVideos = allVideos.stream()
                .filter(video -> categoryId.equals(video.getCategoryId()) && "pass".equals(video.getResult()))
                .collect(Collectors.toList());
            
            // 按发布时间排序（最新优先）
            categoryVideos.sort((v1, v2) -> {
                if (v1.getPublishTime() == null && v2.getPublishTime() == null) {
                    return 0;
                }
                if (v1.getPublishTime() == null) {
                    return 1;
                }
                if (v2.getPublishTime() == null) {
                    return -1;
                }
                return v2.getPublishTime().compareTo(v1.getPublishTime());
            });
            
            // 分页
            int start = (int) pageRequest.getOffset();
            int end = Math.min(start + pageRequest.getPageSize(), categoryVideos.size());
            
            if (start >= categoryVideos.size()) {
                return new ArrayList<>();
            }
            
            return categoryVideos.subList(start, end);
            
        } catch (Exception e) {
            e.printStackTrace();
            return new ArrayList<>();
        }
    }
    
    @Override
    public List<Video> recommendVideosByVideoId(Integer userId, Integer videoId, PageRequest pageRequest) {
        try {
            // 1. 获取当前视频信息
            Video currentVideo = videoService.selectByPrimaryKey(videoId);
            if (currentVideo == null || !"pass".equals(currentVideo.getResult())) {
                // 如果当前视频不存在或未审核通过，返回热门视频
                return getPopularVideos(pageRequest);
            }
            
            // 2. 获取用户行为数据，用于协同过滤
            List<LikeRecord> userLikes = getUserLikes(userId);
            List<CoinRecord> userCoins = getUserCoins(userId);
            List<WatchHistory> userWatchHistory = getUserWatchHistory(userId);
            Map<Integer, Double> userVideoScores = calculateUserVideoScores(userId, userLikes, userCoins, userWatchHistory);
            
            // 3. 获取同分类视频（基于当前视频的相似性）
            List<Video> categorySimilarVideos = getVideosByCategory(currentVideo.getCategoryId(), pageRequest);
            Collections.shuffle(categorySimilarVideos);
            
            // 4. 获取协同过滤推荐视频（基于用户偏好）
            List<Video> collaborativeVideos = new ArrayList<>();
            if (!userVideoScores.isEmpty()) {
                collaborativeVideos = collaborativeFiltering(userId, userVideoScores, pageRequest);
                Collections.shuffle(collaborativeVideos);
            }
            
            // 5. 获取热门视频作为补充
            List<Video> popularVideos = getPopularVideos(pageRequest);
            Collections.shuffle(popularVideos);
            
            // 6. 混合推荐结果
            List<Video> mixedRecommendations = new ArrayList<>();
            
            // 添加同分类视频（40%）
            int categoryCount = Math.min(categorySimilarVideos.size(), (int)(pageRequest.getPageSize() * 0.4));
            mixedRecommendations.addAll(categorySimilarVideos.subList(0, Math.min(categoryCount, categorySimilarVideos.size())));
            
            // 添加协同过滤推荐视频（40%）
            int collaborativeCount = Math.min(collaborativeVideos.size(), (int)(pageRequest.getPageSize() * 0.4));
            mixedRecommendations.addAll(collaborativeVideos.subList(0, Math.min(collaborativeCount, collaborativeVideos.size())));
            
            // 添加热门视频（20%）
            int popularCount = pageRequest.getPageSize() - mixedRecommendations.size();
            if (popularCount > 0 && !popularVideos.isEmpty()) {
                mixedRecommendations.addAll(popularVideos.subList(0, Math.min(popularCount, popularVideos.size())));
            }
            
            // 7. 去重并随机打乱最终结果
            mixedRecommendations = mixedRecommendations.stream()
                .distinct()
                .collect(Collectors.toList());
            Collections.shuffle(mixedRecommendations);
            
            // 8. 限制返回数量
            return mixedRecommendations.stream()
                .limit(pageRequest.getPageSize())
                .collect(Collectors.toList());
                
        } catch (Exception e) {
            e.printStackTrace();
            // 发生异常时返回热门视频
            return getPopularVideos(pageRequest);
        }
    }

    // 辅助方法：获取用户点赞记录
    private List<LikeRecord> getUserLikes(Integer userId) {
        try {
            List<LikeRecord> allLikes = likeRecordService.getAll();
            return allLikes.stream()
                .filter(like -> userId.equals(like.getUserId()) && "video".equals(like.getTargetType()))
                .collect(Collectors.toList());
        } catch (Exception e) {
            return new ArrayList<>();
        }
    }
    

    
    // 辅助方法：获取用户投币记录
    private List<CoinRecord> getUserCoins(Integer userId) {
        try {
            List<CoinRecord> allCoins = coinRecordService.getAll();
            return allCoins.stream()
                .filter(coin -> userId.equals(coin.getUserId()))
                .collect(Collectors.toList());
        } catch (Exception e) {
            return new ArrayList<>();
        }
    }
    
    // 辅助方法：获取用户观看历史
    private List<WatchHistory> getUserWatchHistory(Integer userId) {
        try {
            List<WatchHistory> allHistory = watchHistoryService.getAll();
            return allHistory.stream()
                .filter(history -> userId.equals(history.getUserId()))
                .collect(Collectors.toList());
        } catch (Exception e) {
            return new ArrayList<>();
        }
    }
    
    // 计算用户对视频的兴趣分数
    private Map<Integer, Double> calculateUserVideoScores(Integer userId, 
                                                        List<LikeRecord> likes, 
                                                        List<CoinRecord> coins, 
                                                        List<WatchHistory> watchHistory) {
        Map<Integer, Double> scores = new HashMap<>();
        
        // 点赞权重：1.0
        for (LikeRecord like : likes) {
            scores.merge(like.getTargetId(), 1.0, Double::sum);
        }
        
        // 投币权重：3.0 * 投币数量
        for (CoinRecord coin : coins) {
            double coinScore = 3.0 * (coin.getCoinCount() != null ? coin.getCoinCount() : 1);
            scores.merge(coin.getVideoId(), coinScore, Double::sum);
        }
        
        // 观看权重：0.5
        for (WatchHistory history : watchHistory) {
            scores.merge(history.getVideoId(), 0.5, Double::sum);
        }
        
        return scores;
    }
    
    // 协同过滤推荐算法
    private List<Video> collaborativeFiltering(Integer userId, Map<Integer, Double> userVideoScores, PageRequest pageRequest) {
        try {
            // 获取所有用户的行为数据
            List<LikeRecord> allLikes = likeRecordService.getAll();
            List<CoinRecord> allCoins = coinRecordService.getAll();
            List<WatchHistory> allWatchHistory = watchHistoryService.getAll();
            
            // 构建用户-视频评分矩阵
            Map<Integer, Map<Integer, Double>> userVideoMatrix = buildUserVideoMatrix(allLikes, allCoins, allWatchHistory);
            
            // 找到相似用户
            List<Integer> similarUsers = findSimilarUsers(userId, userVideoScores, userVideoMatrix);
            
            // 基于相似用户推荐视频
            Map<Integer, Double> recommendedScores = new HashMap<>();
            for (Integer similarUserId : similarUsers) {
                Map<Integer, Double> similarUserScores = userVideoMatrix.get(similarUserId);
                if (similarUserScores != null) {
                    for (Map.Entry<Integer, Double> entry : similarUserScores.entrySet()) {
                        Integer videoId = entry.getKey();
                        Double score = entry.getValue();
                        
                        // 跳过用户已经行为过的视频
                        if (!userVideoScores.containsKey(videoId)) {
                            recommendedScores.merge(videoId, score, Double::sum);
                        }
                    }
                }
            }
            
            // 按推荐分数排序
            List<Integer> recommendedVideoIds = recommendedScores.entrySet().stream()
                .sorted(Map.Entry.<Integer, Double>comparingByValue().reversed())
                .limit(pageRequest.getPageSize() * 2L) // 获取更多候选，后续会去重
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
            
            // 获取视频详情
            List<Video> allVideos = videoService.getAll();
            Map<Integer, Video> videoMap = allVideos.stream()
                .collect(Collectors.toMap(Video::getId, video -> video));
            
            List<Video> recommendedVideos = new ArrayList<>();
            for (Integer videoId : recommendedVideoIds) {
                Video video = videoMap.get(videoId);
                if (video != null && "pass".equals(video.getResult())) {
                    recommendedVideos.add(video);
                    if (recommendedVideos.size() >= pageRequest.getPageSize()) {
                        break;
                    }
                }
            }
            
            return recommendedVideos;
            
        } catch (Exception e) {
            e.printStackTrace();
            return new ArrayList<>();
        }
    }
    
    // 构建用户-视频评分矩阵
    private Map<Integer, Map<Integer, Double>> buildUserVideoMatrix(List<LikeRecord> likes, 
                                                                   List<CoinRecord> coins, 
                                                                   List<WatchHistory> watchHistory) {
        Map<Integer, Map<Integer, Double>> matrix = new HashMap<>();
        
        // 处理点赞数据
        for (LikeRecord like : likes) {
            if ("video".equals(like.getTargetType())) {
                matrix.computeIfAbsent(like.getUserId(), k -> new HashMap<>())
                    .merge(like.getTargetId(), 1.0, Double::sum);
            }
        }
        
        // 处理投币数据
        for (CoinRecord coin : coins) {
            double coinScore = 3.0 * (coin.getCoinCount() != null ? coin.getCoinCount() : 1);
            matrix.computeIfAbsent(coin.getUserId(), k -> new HashMap<>())
                .merge(coin.getVideoId(), coinScore, Double::sum);
        }
        
        // 处理观看数据
        for (WatchHistory history : watchHistory) {
            matrix.computeIfAbsent(history.getUserId(), k -> new HashMap<>())
                .merge(history.getVideoId(), 0.5, Double::sum);
        }
        
        return matrix;
    }
    
    // 找到相似用户
    private List<Integer> findSimilarUsers(Integer userId, Map<Integer, Double> userVideoScores, 
                                         Map<Integer, Map<Integer, Double>> userVideoMatrix) {
        List<Map.Entry<Integer, Double>> similarities = new ArrayList<>();
        
        for (Map.Entry<Integer, Map<Integer, Double>> entry : userVideoMatrix.entrySet()) {
            Integer otherUserId = entry.getKey();
            if (!otherUserId.equals(userId)) {
                Map<Integer, Double> otherUserScores = entry.getValue();
                double similarity = calculateCosineSimilarity(userVideoScores, otherUserScores);
                similarities.add(new AbstractMap.SimpleEntry<>(otherUserId, similarity));
            }
        }
        
        // 按相似度排序，返回前10个相似用户
        return similarities.stream()
            .sorted(Map.Entry.<Integer, Double>comparingByValue().reversed())
            .limit(10)
            .map(Map.Entry::getKey)
            .collect(Collectors.toList());
    }
    
    // 计算余弦相似度
    private double calculateCosineSimilarity(Map<Integer, Double> user1Scores, Map<Integer, Double> user2Scores) {
        Set<Integer> allVideos = new HashSet<>();
        allVideos.addAll(user1Scores.keySet());
        allVideos.addAll(user2Scores.keySet());
        // 计算点积和模长
        double dotProduct = 0.0;
        double norm1 = 0.0;
        double norm2 = 0.0;
        
        for (Integer videoId : allVideos) {
            double score1 = user1Scores.getOrDefault(videoId, 0.0);
            double score2 = user2Scores.getOrDefault(videoId, 0.0);
            
            dotProduct += score1 * score2;
            norm1 += score1 * score1;
            norm2 += score2 * score2;
        }
        
        if (norm1 == 0 || norm2 == 0) {
            return 0.0;
        }
        
        return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
    }
    
    // 计算视频热度分数
    private int calculatePopularityScore(Video video) {
        int score = 0;
        score += video.getPlayCount() != null ? video.getPlayCount() : 0;
        score += (video.getLikeCount() != null ? video.getLikeCount() : 0) * 2;
        score += (video.getFavoriteCount() != null ? video.getFavoriteCount() : 0) * 3;
        score += (video.getCoinCount() != null ? video.getCoinCount() : 0) * 5;
        return score;
    }
}